<?php
/**
* 
* ShopWindow Toolset
* 
* Copyright (C) 2008 Digital Window Ltd.
* 
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
* 
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*
*/


require_once('class.soap_client.php');


/**
 * Extends SoapClient and automatically configures settings specific to the AWin API
 *
 */
class api_client
{
	var $oSoapClient; 				// the actuall SOAP client
	var $oResponse;					// the response object, after a succesfull call
	var $oSoapError;				// the SoapError object, if the call produced one

	var $aApiCache			= array(); // caches the returns of the api

	var $aArrayResponses	= array("oCategory","oMerchant","oProduct","iDescendantCategoryId",
									"oActiveRefineByGroup","oQuery", "oRefineByDefinition", "oRefineByGroup");

	/**
	 * The Constructor
	 *
	 * @copyright	DigitalWindow
 	 * @author		Kostas Melas <kostas@digitalwindow.com>
 	 *
	 * @param  void
	 * @return object
	 */
	function api_client()
	{
		// create user object
		$oUser 				= new stdClass();
		$oUser->iId 		= API_USERID;
		$oUser->sPassword 	= API_USERPASS;
		$oUser->sType 		= API_USERTYPE;
		
		$this->oSoapClient  =& soap_client::getInstance($oUser);
	}



	/**
	 * A wrapper for the actual SOAP function call. Also does some basic debugging/error printing
	 *
	 * @copyright	DigitalWindow
 	 * @author		Kostas Melas <kostas@digitalwindow.com>
 	 *
	 * @param 	string 	$sFunctionName
	 * @param 	array	$aParams
	 * 
	 * @return 	object	the SOAP result / fault
	 */
	function call($sFunctionName, $aParams='')
	{
		### STOPWATCH ###
		$fStartTime = $this->getMicroTime();
		
		// pop empty params
		foreach ($aParams as $key => $val) {
			if ( !is_bool($val) && strlen($val) < 1 ) {
				unset($aParams[$key]);
			}
		}


		# try using cache
		// generate hash key
		$sKey = md5($sFunctionName.print_r($aParams, true));
		
		if ( is_object($this->aApiCache[$sKey]) ) {
			// load into obj
			$this->oResponse = $this->aApiCache[$sKey];

			return $this->oResponse;
		}

		$oResponse = $this->oSoapClient->call($sFunctionName, $aParams);

		// check for SoapFaults
		if ( $oResponse instanceof soap_error ) {

			$this->oSoapError = $oResponse;

			// handle SoapFaults
			if ( API_SOAP_ERRORS_PRINT == true ) {
				print "<pre>".print_r($this->oSoapError)."</pre>";
			}
			elseif ( strlen(API_SOAP_ERRORS_REDIRECT_URL) > 5 ) {
				die( header('Location: '.API_SOAP_ERRORS_REDIRECT_URL) );
			}
		}
		else {
			// load into obj
			$this->oResponse = $this->_cleanResponse($oResponse);

			// cache response
			$this->_cacheResponse($sKey, $oResponse);
		}



		// DEBUG
		if ( API_SOAP_DEBUG_PRINT == true ) {
			print '<h3>'.$sFunctionName.' - request</h3>';
			print '<pre>'.print_r($this->oSoapClient->__getLastRequest()).'</pre>';
			print '<h3>'.$sFunctionName.' - response</h3>';

			// calculate performance
			print '<h4>fExecTime: '.($this->getMicroTime() - $fStartTime).'</h4>';

			print '<pre>'.print_r($this->oSoapClient->__getLastResponse()).'</pre>';
		}

		return $oResponse;
	}
	
	/**
	 * Function will clean up SOAP responses. When single item (object) or empty returned where 
	 * array should exist - convert to type array.
	 *
	 * @copyright	DigitalWindow
 	 * @author		Oliver Brennan <obrennan@digitalwindow.com>
 	 *
	 * @param 	object 	$oResponse - SOAP result
	 * 
	 * @return 	object	the clean SOAP result
	 */

	private function _cleanResponse($oResponse)
	{
		// Check is array. If is, check array missing. If object, convert to array //
		foreach ($oResponse as $sAtrName=>$sAtrVal) {
			if ( !empty($oResponse->$sAtrName) && $sAtrVal!==false && !empty($sAtrVal) && 
				(is_array($sAtrVal) || is_object($sAtrVal) )) {
				// Check children too //
				@$oResponse->$sAtrName = $this->_cleanResponse($sAtrVal);
				
				// If is supposed to be array, wrap in array //
				if ( in_array( $sAtrName, $this->aArrayResponses ) && !is_array($oResponse->$sAtrName)) {

					// Check if object not array
					if ( is_object($oResponse->$sAtrName)) {
						// Get object variables 
						$res = get_object_vars($oResponse->$sAtrName);
						
						// Is object empty
						if ( empty($res)) {
							$oResponse->$sAtrName = array();
							continue;
						}
					}
					$oResponse->$sAtrName = array($sAtrVal);
				}
			}
			// Check if empty exists where should be empty array //
			else if ( in_array( $sAtrName, $this->aArrayResponses ) ) {
				$oResponse->$sAtrName = array();
			}
		}

		return $oResponse;
	}


	/**
	 * Caches the response of an API call for future use
	 *
	 * @copyright	DigitalWindow
	 * @author		Kostas Melas <kostas@digitalwindow.com>
	 *
	 * @param 	string 	$sKey
	 * @param 	object	$oResponse
	 * 
	 * @return 	void
	 */
	function _cacheResponse($sKey, $oResponse)
	{
		$this->aApiCache[$sKey] = $oResponse;
	}



	/**
	 * Returns the current time with microseconds
	 *
	 * @copyright	DigitalWindow
	 * @author		Kostas Melas <kostas@digitalwindow.com>
	 *
	 * @param 	void
	 * 
	 * @return 	float
	 */
	function getMicroTime()
	{
	   list($msec, $sec) = explode(" ", microtime());
	   $fMicroTime = (float)$msec + (float)$sec;
	
	   return  $fMicroTime;
	}



	/**
	 * Renaming and removing of categories
	 *
	 * @copyright	DigitalWindow
	 * @author		Oliver Brennan <obrennan@digitalwindow.com>
	 *
	 * @param 		object $oCategory - Returns the processed category
	 *
	 * @return 		array	the modified categories
	 */
	function filterCategories($aCategories)
	{
		$aCategoryMappings = unserialize(CATEGORY_MAPPINGS);

		foreach ($aCategories as $key => $oCategory) {
			// rename/remove categories found in array
			if ( array_key_exists($oCategory->iId, $aCategoryMappings) ) {
				
				$oCategory->sName = $aCategoryMappings[$oCategory->iId];
				
				// pop on empty name
				if ( empty($oCategory->sName) ) {
					unset($aCategories[$key]);
					continue;
				}
			}

			// adult filter
			if ( ADULT_CONTENT === false && $oCategory->bAdult == true ) {
				unset($aCategories[$key]);
				continue;
			}
		}

		return $aCategories;
	}

} // end class

?>